package com.scheduler.backend.blImpl;


import com.scheduler.backend.aps.domain.deadlinefirst.ScheduleTable;
import com.scheduler.backend.bl.OrderService;
import com.scheduler.backend.data.repository.*;
import com.scheduler.backend.po.*;
import com.scheduler.backend.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.jni.Local;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    private static Logger logger = (Logger) LoggerFactory.getLogger(OrderServiceImpl.class);

    private LocalDateTime scheduleStartTime = LocalDateTime.of(LocalDate.of(2018, 10, 14),
            LocalTime.of(7, 0, 0));;//todo 未来修改

    @Autowired
    private ResourceRepository resourceRepository;

    @Autowired
    private ResourceGroupRepository resourceGroupRepository;

    @Autowired
    private OrderSliceRepository orderSliceRepository;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private CraftRepository craftRepository;

    @Autowired
    private ItemProcessRepository itemProcessRepository;

    @Override
    public ResponseVO getOrderGanttByDate(Date date) {
        try{
            List<OrderGanttInfo> orderGanttInfoList = new ArrayList<>();
            List<Order> orderList = orderRepository.findAll();
            List<OrderSlicePO> orderSliceList = orderSliceRepository.findAll();
            orderSliceList.sort(Comparator.comparingLong(OrderSlicePO::getStartTimeSlot));
            List<Craft> craftList = craftRepository.findAll();

            for (int i=0;i<orderList.size();i++){
                Order order = orderList.get(i);
                OrderGanttInfo orderGanttInfo = new OrderGanttInfo();
                orderGanttInfo.setOrderID(order.getOrderId());
                String state="";

                LocalDateTime ddl = order.getDeadline().toInstant()
                        .atZone( ZoneId.systemDefault() )
                        .toLocalDateTime();
                LocalDateTime today = date.toInstant()
                        .atZone( ZoneId.systemDefault() )
                        .toLocalDateTime();
                LocalDateTime completeDay = order.getDeadline().toInstant()
                        .atZone( ZoneId.systemDefault() )
                        .toLocalDateTime().plusDays(1);

                for (int j=orderSliceList.size()-1;j>=0;j--){
                    if (!orderSliceList.get(j).getOrderID().equals(order.getOrderId().toString())) continue;
                    LocalDateTime endTime = scheduleStartTime.plusSeconds((orderSliceList.get(j).getStartTimeSlot() + ScheduleTable.ORDER_SLICE_TIMESLOT_SPAN ) * 60 * ScheduleTable.ORDER_SLICE_MINUTES);
                    completeDay = endTime;
                    break;
                }

                if (!completeDay.toLocalDate().isAfter(ddl.toLocalDate()) && !today.toLocalDate().isBefore(completeDay.toLocalDate()) ){
                    state = "已完成";
                }else if (completeDay.toLocalDate().isAfter(ddl.toLocalDate()) && !today.toLocalDate().isBefore(completeDay.toLocalDate()) ){
                    state = "已延期";
                }else {
                    state = "正在完成";
                }
                orderGanttInfo.setState(state);
                List<ArtifactInfo> stepList = new ArrayList<>();


                for (int j=0;j<craftList.size();j++){
                    if (!craftList.get(j).getProductId().equals(order.getItemId())) continue;
                    ArtifactInfo artifactInfo = new ArtifactInfo();
                    artifactInfo.setStepName(craftList.get(j).getArtifactName());
                    double delayProgress = 0.0;
                    double normalProgress = 0.0;
                    double weight = 0.0;
                    int totNum=0;
                    int delayNum=0;
                    int normalNum=0;
                    double weightSumUp=0.0;
                    double weightSumDown=0.0;
                    //修复权重的计算方式(希望吧)
                    for (int k=0;k<orderSliceList.size();k++){
                        if (!orderSliceList.get(k).getOrderID().equals(order.getOrderId().toString())) continue;
                        totNum++;

                        LocalDateTime endTime = scheduleStartTime.plusSeconds((orderSliceList.get(k).getStartTimeSlot() + ScheduleTable.ORDER_SLICE_TIMESLOT_SPAN ) * 60 * ScheduleTable.ORDER_SLICE_MINUTES);


                        if (!endTime.toLocalDate().isAfter(today.toLocalDate())){
                            weightSumDown+=ScheduleTable.ORDER_SLICE_TIMESLOT_SPAN * 60 * ScheduleTable.ORDER_SLICE_MINUTES;
                            if (orderSliceList.get(k).getCraftName().equals(craftList.get(j).getArtifactName())){
                                weightSumUp+=ScheduleTable.ORDER_SLICE_TIMESLOT_SPAN * 60 * ScheduleTable.ORDER_SLICE_MINUTES;
                            }
                            if (!endTime.toLocalDate().isAfter(ddl.toLocalDate())){
                                normalNum++;
                            }else{
                                delayNum++;
                            }
                        }
                    }
                    if (totNum!=0){
                        delayProgress = (double)delayNum/(double)totNum;
                        normalProgress = (double)normalNum/(double)totNum;
                    }

                    weight = 1.0;
                    if (weightSumDown>0.0){
                        weight = weightSumUp/weightSumDown;
                    }

                    weight = (double) Math.round(weight * 1000) / 10;
                    delayProgress = (double) Math.round(delayProgress * 1000) / 10;
                    normalProgress = (double) Math.round(normalProgress * 1000) / 10;
                    artifactInfo.setDelayProgress(delayProgress);
                    artifactInfo.setNormalProgress(normalProgress);
                    artifactInfo.setWeight(weight);
                    stepList.add(artifactInfo);
                }

                orderGanttInfo.setStepList(stepList);
                boolean pd = false;
                for (int j=0;j<stepList.size();j++){
                    if (stepList.get(j).getNormalProgress()>0.0){
                        pd=true;
                        break;
                    }else if (stepList.get(j).getDelayProgress()>0.0){
                        pd=true;
                        break;
                    }
                }
                if (pd){
                    orderGanttInfoList.add(orderGanttInfo);
                }
            }

            return ResponseVO.buildSuccess(orderGanttInfoList);
        }catch (Exception e){
            return ResponseVO.buildFailure("getOrderGanttByDate Failed!");
        }
    }

    @Override
    public ResponseVO getNewOrders(Date date) {
        try{
            List<NewOrderVO> newOrderVOList = new ArrayList<>();
            List<Order> orderList = orderRepository.findAll();
            List<OrderSlicePO> orderSlicePOList = orderSliceRepository.findAll();
            for (int i=0;i<orderList.size();i++){
                String id0 = orderList.get(i).getOrderId().toString();
                String productId = orderList.get(i).getItemId();
                int productNum = orderList.get(i).getOrderNum();
                Date ddl = orderList.get(i).getDeadline();
                if (orderList.get(i).getDeleted().equals(1)) continue;
                boolean isExist = false;
                for (int j=0;j<orderSlicePOList.size();j++){
                    String id1 = orderSlicePOList.get(j).getOrderID();
                    if (id0.equals(id1)){
                        isExist = true;
                        break;
                    }
                }
                if (!isExist){
                    NewOrderVO vo = new NewOrderVO();
                    vo.setOrderId(id0);
                    vo.setProductId(productId);
                    vo.setProductNum(productNum);
                    vo.setDeadline(new SimpleDateFormat("yyyy-MM-dd").format(ddl));
                    newOrderVOList.add(vo);
                }
            }
            return ResponseVO.buildSuccess(newOrderVOList);
        }catch (Exception e){
            return ResponseVO.buildFailure("getNewOrders Failed!");
        }
    }

    @Override
    public ResponseVO getAllOrders(Date date) {
        try{
            List<AllOrderVO> allOrderVOList = new ArrayList<>();
            List<Order> orderList = orderRepository.findAll();
            List<OrderSlicePO> orderSlicePOList = orderSliceRepository.findAll();
            for (int i=0;i<orderList.size();i++){
                String id0 = orderList.get(i).getOrderId().toString();
                String productId = orderList.get(i).getItemId();
                int productNum = orderList.get(i).getOrderNum();
                Date ddl = orderList.get(i).getDeadline();
                if (orderList.get(i).getDeleted().equals(1)) continue;
                boolean isExist = false;
                for (int j=0;j<orderSlicePOList.size();j++){
                    String id1 = orderSlicePOList.get(j).getOrderID();
                    if (id0.equals(id1)){
                        isExist = true;
                        break;
                    }
                }
                if (isExist){
                    AllOrderVO vo = new AllOrderVO();
                    vo.setOrderId(id0);
                    vo.setProductId(productId);
                    vo.setProductNum(productNum);
                    vo.setDeadline(new SimpleDateFormat("yyyy-MM-dd").format(ddl));
                    int status = 0;
                    LocalDateTime startTime=null;
                    LocalDateTime endTime=null;
                    LocalDateTime today = date.toInstant()
                            .atZone( ZoneId.systemDefault() )
                            .toLocalDateTime().plusDays(1);
                    LocalDateTime localDDL = ddl.toInstant()
                            .atZone( ZoneId.systemDefault() )
                            .toLocalDateTime();
                    int minSlot = 99999999;
                    int maxSlot = -1;
                    for (int j=0;j<orderSlicePOList.size();j++){
                        String id1 = orderSlicePOList.get(j).getOrderID();
                        if (id0.equals(id1)){
                            int slot = (int)orderSlicePOList.get(j).getStartTimeSlot();
                            if (slot > maxSlot) maxSlot=slot;
                            if (slot < minSlot) minSlot=slot;
                        }
                    }
                    startTime = scheduleStartTime.plusSeconds((minSlot) * 60 * ScheduleTable.ORDER_SLICE_MINUTES);
                    endTime = scheduleStartTime.plusSeconds((maxSlot + ScheduleTable.ORDER_SLICE_TIMESLOT_SPAN ) * 60 * ScheduleTable.ORDER_SLICE_MINUTES);
                    if (!endTime.isAfter(today)&&!endTime.isAfter(localDDL)){
                        vo.setStatus(2);
                    }else if (startTime.isAfter(today)){
                        vo.setStatus(0);
                    }else if (!endTime.isAfter(today)&&endTime.isAfter(localDDL)){
                        vo.setStatus(3);
                    }else{
                        vo.setStatus(1);
                    }
                    allOrderVOList.add(vo);
                }
            }
            return ResponseVO.buildSuccess(allOrderVOList);
        }catch (Exception e){
            return ResponseVO.buildFailure("getAllOrders Failed!");
        }
    }


    @Override
    public ResponseVO getAllProducts() {
        try{
            List<ProductIdVO> productIdVOList = new ArrayList<>();
            List<ItemProcess> itemProcessList = itemProcessRepository.findAll();
            LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
            for (int i=0;i<itemProcessList.size();i++){
                String productId = itemProcessList.get(i).getProductId();
                if (!map.containsKey(productId)){
                    map.put(productId,1);
                }
            }
            for (String key: map.keySet()
                 ) {
                ProductIdVO vo =new ProductIdVO();
                vo.setProductId(key);
                productIdVOList.add(vo);
            }
            return ResponseVO.buildSuccess(productIdVOList);
        }catch (Exception e){
            return ResponseVO.buildFailure("getAllOrders Failed!");
        }
    }

    @Override
    public ResponseVO getOrderGantt(Date date, String orderId) {
        try{
            List<OrderGanttRatioVO> orderGanttRatioVOList=new ArrayList<>();

            List<OrderSlicePO> orderSlicePOList=orderSliceRepository.findAll();
            LinkedHashMap<String,Integer> map = new LinkedHashMap<>();//阶段map
            int sumSlice = 0;
            for (int i=0;i<orderSlicePOList.size();i++){
                if (!orderSlicePOList.get(i).getOrderID().equals(orderId)) continue;
                sumSlice++;
                if (map.containsKey(orderSlicePOList.get(i).getCraftName())) continue;
                map.put(orderSlicePOList.get(i).getCraftName(),1);
            }


            LocalDateTime today=date.toInstant()
                    .atZone( ZoneId.systemDefault() )
                    .toLocalDateTime().plusDays(1);



            for (String key:map.keySet()) {
                OrderGanttRatioVO vo = new OrderGanttRatioVO();
                vo.setName(key);
                int sumCraft=0;
                int curCraft=0;
                for (int i=0;i<orderSlicePOList.size();i++){
                    if (!orderSlicePOList.get(i).getOrderID().equals(orderId)) continue;
                    if (!orderSlicePOList.get(i).getCraftName().equals(key)) continue;
                    sumCraft++;
                    LocalDateTime edTime = scheduleStartTime.plusSeconds((orderSlicePOList.get(i).getStartTimeSlot() + ScheduleTable.ORDER_SLICE_TIMESLOT_SPAN ) * 60 * ScheduleTable.ORDER_SLICE_MINUTES);
                    if (!edTime.isAfter(today)) curCraft++;
                }

                double curRatio = 0.0;
                if (sumCraft!=0){
                    curRatio = (double)((double)curCraft)/((double)sumCraft);
                }
                curRatio = (double) Math.round(curRatio * 1000) / 10;
                vo.setCurRatio(curRatio);

                double ratio = 0.0;
                if (sumSlice !=0){
                    ratio = (double)((double)sumCraft)/((double)sumSlice);
                }
                ratio = (double) Math.round(ratio * 1000) / 10;
                vo.setRatio(ratio);
                orderGanttRatioVOList.add(vo);
            }

            return ResponseVO.buildSuccess(orderGanttRatioVOList);
        }catch (Exception e){
            return ResponseVO.buildFailure("getOrderGantt Failed!");
        }
    }


    //删除订单
    @Override
    public ResponseVO deleteOrder(String orderIdList) {
        try{
            String[] orderIdArr=orderIdList.split(",");
            for(int i=0;i<orderIdArr.length;i++) {
                String orderId=orderIdArr[i];
                Integer int_orderId = Integer.parseInt(orderId);
                Order order = orderRepository.getOne(int_orderId);
                if (order != null) {
                    order.setDeleted(1);
                    orderRepository.save(order);
                }
            }
            return ResponseVO.buildSuccess();
        }catch (Exception e){
            e.printStackTrace();
            return ResponseVO.buildFailure("delete order Failed!");
        }
    }

    //增加/修改订单
    @Override
    public ResponseVO addOrder(String orderId,String productId,int productNum,Date deadline) {
        try{
            if(!orderId.equals("-")) {
                int int_orderId = Integer.parseInt(orderId);

                Order order = new Order(int_orderId, productId, productNum, deadline, 0);
                orderRepository.save(order);
            }else{
               long seconds=System.currentTimeMillis();

               String fake_str=Long.toString(seconds);
               String new_orderId=fake_str.substring(fake_str.length()-6,fake_str.length());

                Order order=new Order(Integer.parseInt(new_orderId),productId,productNum,deadline,0);
                orderRepository.save(order);
            }
                return ResponseVO.buildSuccess();
        }catch (Exception e){
            e.printStackTrace();
            return ResponseVO.buildFailure("add order "+orderId+" Failed!");
        }
    }

}